#include "xsdl.h"
#include <SDL.h>
#include <iostream>
#include "xvideo_view.h"
using namespace std;
XSDL::XSDL()
{
}
static bool InitVideo()
{
    static bool is_first = true;
    static mutex mutex_;
    unique_lock<std::mutex> lock(mutex_);
    if (!is_first)
    {
        return true;
    }
    is_first = false;
    if (SDL_Init(SDL_INIT_VIDEO))
    {
        cout << "SDL_Init Error: " << SDL_GetError() << endl;
        return false;
    }
    // 设置缩放算法
    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
    return true;
}
bool XSDL::Init(int w, int h, Format fmt)
{
    if (w <= 0 || h <= 0)
        return false;
    InitVideo();
    // 确保线程安全
    std::unique_lock<std::mutex> lock(mutex_);
    width_ = w;
    height_ = h;
    fmt_ = fmt;
    if (!win_)
    {
        // 生成窗口
        if (!win_id_)
            win_ = SDL_CreateWindow("SDL2-test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
        else
        {
            win_ = SDL_CreateWindowFrom(win_id_);
        }
    }
    if (!win_)
    {
        cout << "SDL_CreateWindow Error: " << SDL_GetError() << endl;
        return false;
    }
    if (texture_)
    {
        SDL_DestroyTexture(texture_);
        texture_ = nullptr;
    }
    if (!renderer_)
    {
        // 创建渲染器
        renderer_ = SDL_CreateRenderer(win_, -1, SDL_RENDERER_ACCELERATED);
    }
    if (!renderer_)
    {
        std::string s = std::string("SDL_CreateTexture Error: ") + SDL_GetError();
        cout << s << endl;
        return false;
    }
    // 创建纹理
    unsigned int sdl_fmt = SDL_PIXELFORMAT_RGB24;
    switch (fmt)
    {
    case RGBA:
        sdl_fmt = SDL_PIXELFORMAT_RGBA32;
        break;
    case ARGB:
        sdl_fmt = SDL_PIXELFORMAT_ARGB32;
        break;
    case BGRA:
        sdl_fmt = SDL_PIXELFORMAT_BGRA32;
        break;
    case YUV420P:
        sdl_fmt = SDL_PIXELFORMAT_IYUV;
        break;
    default:
        break;
    }
    texture_ = SDL_CreateTexture(renderer_, sdl_fmt, SDL_TEXTUREACCESS_STREAMING, w, h);
    if (!texture_)
    {
        std::string s = std::string("SDL_CreateTexture Error: ") + SDL_GetError();
        cout << s << endl;
        return false;
    }
    return true;
}

bool XSDL::Draw(const uint8_t *data, int linesize)
{
    if (!data)
    {
        return true;
    }
    unique_lock<std::mutex> lock(mutex_);
    if (!texture_ || !renderer_ || !win_ || width_ <= 0 || height_ <= 0)
        return false;
    if (linesize <= 0)
    {
        switch (fmt_)
        {
        case RGBA:
        case ARGB:
            linesize = width_ * 4;
            break;
        case YUV420P:
            linesize = width_;
            break;
        default:
            break;
        }
    }
    if (linesize <= 0)
        return false;
    auto ret = SDL_UpdateTexture(texture_, nullptr, data, linesize);
    if (ret != 0)
    {
        cout << "SDL_UpdateTexture Error: " << SDL_GetError() << endl;
        return false;
    }
    ret = SDL_RenderClear(renderer_);
    if (ret != 0)
    {
        cout << "SDL_RenderClear Error: " << SDL_GetError() << endl;
        return false;
    }
    SDL_Rect rect;
    SDL_Rect *p_rect = nullptr;
    if (scale_h_ > 0 && scale_w_ > 0)
    {
        rect = {0, 0, scale_w_, scale_h_};
        p_rect = &rect;
    }
    ret = SDL_RenderCopy(renderer_, texture_, nullptr, p_rect);
    if (ret != 0)
    {
        cout << "SDL_RenderCopy Error: " << SDL_GetError() << endl;
        return false;
    }
    SDL_RenderPresent(renderer_);
    return true;
}

bool XSDL::Draw(const uint8_t *y, int y_pitch, const uint8_t *u, int u_pitch, const uint8_t *v, int v_pitch)
{
    // 参数检查
    if (!y || !u || !v || y_pitch <= 0 || u_pitch <= 0 || v_pitch <= 0)
    {
        return true;
    }
    unique_lock<std::mutex> lock(mutex_);
    if (!texture_ || !renderer_ || !win_ || width_ <= 0 || height_ <= 0)
        return false;
    auto ret = SDL_UpdateYUVTexture(texture_, nullptr, y, y_pitch, u, u_pitch, v, v_pitch);
    if (ret != 0)
    {
        cout << "SDL_UpdateTexture Error: " << SDL_GetError() << endl;
        return false;
    }
    ret = SDL_RenderClear(renderer_);
    if (ret != 0)
    {
        cout << "SDL_RenderClear Error: " << SDL_GetError() << endl;
        return false;
    }
    SDL_Rect rect;
    SDL_Rect *p_rect = nullptr;
    if (scale_h_ > 0 && scale_w_ > 0)
    {
        rect = {0, 0, scale_w_, scale_h_};
        p_rect = &rect;
    }
    ret = SDL_RenderCopy(renderer_, texture_, nullptr, p_rect);
    if (ret != 0)
    {
        cout << "SDL_RenderCopy Error: " << SDL_GetError() << endl;
        return false;
    }
    SDL_RenderPresent(renderer_);
    return true;
}

void XSDL::Close()
{
    unique_lock<std::mutex> lock(mutex_);
    if (texture_)
    {
        SDL_DestroyTexture(texture_);
        texture_ = nullptr;
    }
    if (renderer_)
    {
        SDL_DestroyRenderer(renderer_);
        renderer_ = nullptr;
    }
    if (win_)
    {
        SDL_DestroyWindow(win_);
        win_ = nullptr;
    }
}

bool XSDL::IsExit()
{
    SDL_Event event;
    SDL_WaitEventTimeout(&event, 1);
    if (event.type == SDL_QUIT)
    {
        return true;
    }
    return false;
}
